package com.biostime.qdingding.modules.job.service;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.biostime.qdingding.common.service.BaseService;
import com.biostime.qdingding.common.utils.StringUtils;
import com.biostime.qdingding.modules.job.dao.AutoClearDao;
import com.biostime.qdingding.modules.qd.entity.Course;
import com.biostime.qdingding.modules.qd.entity.Orderpromotions;
import com.biostime.qdingding.modules.qd.entity.Privilege;
import com.biostime.qdingding.modules.qd.entity.Promotion;
import com.biostime.qdingding.modules.qd.entity.Transrecord;
import com.biostime.qdingding.modules.qd.entity.Course.PriceType;
import com.biostime.qdingding.modules.qd.push.MsgTemplate;
import com.biostime.qdingding.modules.qd.push.MsgTemplate.Fee;
import com.biostime.qdingding.modules.qd.service.CourseOrderService;
import com.biostime.qdingding.modules.qd.service.MemberCouponService;
import com.biostime.qdingding.modules.qd.service.MessageService;
import com.biostime.qdingding.modules.qd.service.OrderpromotionsService;
import com.biostime.qdingding.modules.qd.service.PrivilegeService;
import com.biostime.qdingding.modules.qd.service.PrivrecordService;
import com.biostime.qdingding.modules.qd.service.TransrecordService;
import com.biostime.qdingding.modules.sys.entity.User;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 自动结算Service
 * @author phil
 * @version 2015-11-25
 */
@Service
@Transactional(readOnly = true)
public class AutoClearHandler extends BaseService {
	
	/**
	 * 日志对象
	 */
	protected Logger logger = LoggerFactory.getLogger("autoclear");
	
	@Autowired 
	private CourseOrderService courseOrderService;
	@Autowired
	private TransrecordService transrecordService;
	@Autowired
	private OrderpromotionsService orderpromotionsService;
	@Autowired
	private AutoClearDao autoClearDao;
	@Autowired
	private MessageService messageService;
	@Autowired
	private PrivilegeService privilegeService;
	@Autowired
	private PrivrecordService privrecordService;
	@Autowired
	private MemberCouponService memberCouponService;
	
	/**
	 * http://stackoverflow.com/questions/28480480/propagation-requires-new-does-not-create-a-new-transaction-in-spring-with-jpa
	 * @return
	 */
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public boolean handleOrderIn(int type, Course course, int orderdCount, HashMap<String,Object> orderedStudent, StringBuilder log){
		
		int memberId = StringUtils.toInteger(orderedStudent.get("memberId"));//会员编号
		int studentId = StringUtils.toInteger(orderedStudent.get("studentId")); //学员编号
		int orderId = StringUtils.toInteger(orderedStudent.get("id"));//订单编号
		int contractId = StringUtils.toInteger(orderedStudent.get("contractId"));//合同编号
		int rank = StringUtils.toInteger(orderedStudent.get("rank"));//约课排名
		int priceType = StringUtils.toInteger(orderedStudent.get("priceType"));//课程类型
		int centerId = StringUtils.toInteger(orderedStudent.get("centerId"));//早教中心编号
		int memberCounponId = StringUtils.toInteger(orderedStudent.get("couponId"));//优惠券编号
		String state = (String)orderedStudent.get("state");
		
		String price = orderedStudent.get("price").toString();//价格
		
		log.append(String.format("====>预约课程ID(%s),排名(%s)\n", orderId, rank));
		
		boolean hasError = false;//是否有错误
		
		/**第一步：确定课程的真实价格**/
		double payMoney = 0d; //课程真实价格
		
		ObjectMapper maper = new ObjectMapper();
		List<PriceType> floatPrice = null;
		
		log.append(String.format("====>价格类型:%s, 浮动价格:%s\n", priceType, price));
		
		try {
			floatPrice = Arrays.asList((maper.readValue(price, PriceType[].class)));
		} catch (Exception e) {
			hasError = true;
			log.append(String.format("====>价格Json转换出现异常：%s,%s\n", type, course.getId(), e.getMessage(), e.getStackTrace()));
		}
		
		if(floatPrice==null || floatPrice.size()==0){
			hasError = true;
			log.append(String.format("====>课程价格未设置或格式错误\n", type, course.getId()));
		}
		
		if(orderdCount>course.getCapacity()){
			orderdCount = course.getCapacity();
		}
		
		if(priceType==0){
			//忙时价格
			payMoney = floatPrice.get(0).getPrice();
		}else{
			//闲时价格
			for(PriceType pt : floatPrice){
				if(orderdCount>= pt.getStarton() && orderdCount<= pt.getEndon()){
					payMoney = pt.getPrice();
				}
			}
		}
		
		log.append(String.format("====>浮动价格:%s\n", payMoney));
		
		if(hasError){  
			logger.info(log.toString());
			return false;
		}
		
		/**第二步：计算优惠**/
		List<Promotion> promotions = autoClearDao.getPromotions(studentId);
		
		//Course course = new Course(String.valueOf(course.getId()));
		course.clearPromotions();//清除掉之前的打折
		course.setRank(rank);
		
		if(promotions!=null && promotions.size()>0){
			
			course.setPriceNow(payMoney);
			course.setStudentId(studentId);
			course.setPriceType(priceType);
			//设置优惠
			course.addPromotions(promotions);
			//打折
			course.discount();
			
			for(Promotion promotion : promotions){
				if(course.getPromotions().containsKey(promotion.getTemplate().getFormula())){
					log.append(String.format("====>[ID(%s) %s]优惠金额：%s元(优惠前：%s元,优惠后：%s元,)\n",
							promotion.getId(), promotion.getPromotionName(),promotion.getMoney(),promotion.getPreMoney(), 
							(promotion.getPreMoney()-promotion.getMoney())));
					
					//生成优惠记录
					Orderpromotions op = new Orderpromotions();
					op.setCourseorderId(orderId); //预约课程编号
					op.setPromotionId(StringUtils.toInteger(promotion.getId())); //促销编号
					op.setMoney(promotion.getMoney()); //促销金额
					op.setDescription(String.format("[%s]优惠金额：%s元(优惠前：%s元,优惠后：%s元)",promotion.getPromotionName(), promotion.getMoney(), promotion.getPreMoney(), (promotion.getPreMoney()-promotion.getMoney()))); //描述
					op.setCenterId(centerId); //早教中心
					op.setCreateBy(new User("0"));
					op.setCreateDate(new Date());
					op.setUpdateBy(new User("0"));
					op.setUpdateDate(new Date());
					orderpromotionsService.save(op);
				}else{
					log.append(String.format("====>由于课程忽略该优惠，跳过［ID(%s)%s］优惠金额：%s元(优惠前：%s元,优惠后：%s元)\n",promotion.getId(), promotion.getPromotionName(),promotion.getMoney(),promotion.getPreMoney(), (promotion.getPreMoney()-promotion.getMoney())));
				}
			}
		}
		
		/**判断是否有请假特权**/
		boolean hasLeaveRight = false;
		if(state.equals("leaved")){
			Privilege priv = privilegeService.apiGetPrivilege("leave", String.valueOf(contractId));
			if(priv!=null && (priv.getTotal()-priv.getUsed())>0){
				hasLeaveRight = true;
				
				//生成请假纪录
				privilegeService.apiUpdatePrivilege(priv.getId(), priv.getUsed()+1);
				privrecordService.apiInsert(String.valueOf(centerId), String.valueOf(contractId), priv.getId(), String.valueOf(orderId));
				
				log.append(String.format("====>有请假特权,生成请假记录\n"));
			}
		}
		
		if(!hasLeaveRight){
			log.append(String.format("====>无请假特权\n"));
		}
		
		boolean hasCoupon = false;
		String couponType = "";
		String couponName = "";
		/**判断是否有优惠券**/
		if(memberCounponId != 0){
			List<Map<String,Object>> coupons = autoClearDao.getCoupon(memberCounponId);
			
			if(coupons!=null && coupons.size()>0){
				couponType = coupons.get(0).get("type").toString();
				couponName = coupons.get(0).get("name").toString();
				
				hasCoupon = true;
				
				//约课时已经标示优惠券已经被使用（20160323）
				/*int isUsed = StringUtils.toInteger(coupons.get(0).get("isUsed"));
				if(isUsed==0){
					hasCoupon = true;
					
					memberCouponService.used(memberCounponId);
				}*/
			}
		}
		
		if(hasCoupon){
			log.append(String.format("====>有优惠券[%s,%s]\n",couponType, couponName));
		}else{
			log.append(String.format("====>无优惠券\n"));
		}
		
		if(hasLeaveRight && hasCoupon){
			log.append(String.format("====>有请假特权,归还优惠券[%s,%s]\n",couponType, couponName));
			
			hasCoupon = false;
			memberCouponService.used(memberCounponId, 0);
		}
		
		/**第三步：生成交易记录**/
		SimpleDateFormat df = new SimpleDateFormat("MM月dd日");
		Date now = new Date();
		
		Transrecord tr = new Transrecord();
		tr.setInout(1);// 收支类型，0收，1支 (以会员的角度)
		//3	普通课程
		//4	户外课程
		tr.setType("3");//交易类型 支的有：普通课程、户外课程； 收的有：1充值（即合同支付）、2请假资格返还、3取消资格返还，
		
		if(hasCoupon){
			tr.setMoney(0D); // 交易金额
		}else{
			tr.setMoney(hasLeaveRight ? 0 : course.getPriceNow()); // 交易金额
		}
		
		/*1	微信支付
		2	支付宝支付
		3	银联在线支付
		4	系统返还
		5	系统扣费
		6	现金支付*/
		tr.setPayType("5"); //支付方式（微信，支付宝，银联，现金）
		//tr.setPayCode("－"); //支付单号
		tr.setPayDate(new Date()); //发生日期
		
		if(hasCoupon){
			tr.setDescription(String.format("[%s %s%s]自动扣费, 使用%s",df.format(course.getOndate()), course.getClevel(), course.getSerial(), couponName)); //描述
		}else{
			tr.setDescription(String.format((hasLeaveRight ? "[%s %s%s]自动扣费,使用请假特权":"[%s %s%s]自动扣费"),df.format(course.getOndate()), course.getClevel(), course.getSerial())); //描述
		}
		
		tr.setMemberId(memberId); //会员编号
		tr.setStudentId(studentId); //学员编号
		tr.setCourseorderId(orderId); //预约课程编号
		tr.setContractId(contractId); //合同编号
		tr.setInvalid(0); //是否作废
		tr.setCenterId(centerId);//早教中心
		tr.setCreateBy(new User("0"));
		tr.setCreateDate(now);
		tr.setUpdateBy(new User("0"));
		tr.setUpdateDate(now);
		transrecordService.save(tr);
		
		log.append(String.format("====>生成交易记录(%s)，自动扣费：%s元\n",tr.getId(), tr.getMoney()));
		//throw new RuntimeException();
		//logger.info(log.toString());
		
		/**第四步:发送扣费成功信息**/
		if(hasLeaveRight){
			String message = Fee.content_;
			message = message.replace(MsgTemplate.price,  String .format("%.1f",tr.getMoney()));
			message = message.replace(MsgTemplate.date, df.format(course.getOndate()));
			message = message.replace(MsgTemplate.section, course.getSection());
			message = message.replace(MsgTemplate.level, course.getClevel());
			message = message.replace(MsgTemplate.serial, course.getSerial());
			message = message.replace(MsgTemplate.theme, course.getTheme());
			
			String pushMsg = Fee.push_;
			pushMsg = pushMsg.replace(MsgTemplate.price,  String .format("%.1f",tr.getMoney()));
			pushMsg = pushMsg.replace(MsgTemplate.date, df.format(course.getOndate()));
			pushMsg = pushMsg.replace(MsgTemplate.section, course.getSection());
			pushMsg = pushMsg.replace(MsgTemplate.level, course.getClevel());
			pushMsg = pushMsg.replace(MsgTemplate.serial, course.getSerial());
			pushMsg = pushMsg.replace(MsgTemplate.theme, course.getTheme());
			
			messageService.sendAndPush(Fee.category, String.valueOf(studentId), Fee.title, message, String.valueOf(memberId), pushMsg);
		}else{
			String message = Fee.content;
			message = message.replace(MsgTemplate.price,  String .format("%.1f",tr.getMoney()));
			message = message.replace(MsgTemplate.date, df.format(course.getOndate()));
			message = message.replace(MsgTemplate.section, course.getSection());
			message = message.replace(MsgTemplate.level, course.getClevel());
			message = message.replace(MsgTemplate.serial, course.getSerial());
			message = message.replace(MsgTemplate.theme, course.getTheme());
			
			String pushMsg = Fee.push;
			pushMsg = pushMsg.replace(MsgTemplate.price,  String .format("%.1f",tr.getMoney()));
			pushMsg = pushMsg.replace(MsgTemplate.date, df.format(course.getOndate()));
			pushMsg = pushMsg.replace(MsgTemplate.section, course.getSection());
			pushMsg = pushMsg.replace(MsgTemplate.level, course.getClevel());
			pushMsg = pushMsg.replace(MsgTemplate.serial, course.getSerial());
			pushMsg = pushMsg.replace(MsgTemplate.theme, course.getTheme());
			
			messageService.sendAndPush(Fee.category, String.valueOf(studentId), Fee.title, message, String.valueOf(memberId), pushMsg);
		}
		log.append(String.format("====>发送并推送消息\n",tr.getId(), tr.getMoney()));
		
		return true;
	}
	
	/**
	 * http://stackoverflow.com/questions/28480480/propagation-requires-new-does-not-create-a-new-transaction-in-spring-with-jpa
	 * @return
	 */
	@Deprecated
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public boolean handleOrderOut(int type,int courseId, int orderdCount, HashMap<String,Object> orderedStudent, StringBuilder log){
		
		int memberId = StringUtils.toInteger(orderedStudent.get("memberId"));//会员编号
		int studentId = StringUtils.toInteger(orderedStudent.get("studentId")); //学员编号
		int orderId = StringUtils.toInteger(orderedStudent.get("id"));//订单编号
		int contractId = StringUtils.toInteger(orderedStudent.get("contractId"));//合同编号
		int rank = StringUtils.toInteger(orderedStudent.get("rank"));//约课排名
		int priceType = StringUtils.toInteger(orderedStudent.get("priceType"));//课程类型
		String price = orderedStudent.get("price").toString();//价格
		
		log.append(String.format("====>预约课程ID(%s),排名(%s)\n", orderId, rank));
		
		boolean hasError = false;//是否有错误
		
		/**第一步：确定课程的真实价格**/
		double payMoney = 0d; //课程真实价格
		
		ObjectMapper maper = new ObjectMapper();
		List<PriceType> floatPrice = null;
		
		log.append(String.format("====>价格类型:%s, 浮动价格:%s\n", priceType, price));
		
		try {
			floatPrice = Arrays.asList((maper.readValue(price, PriceType[].class)));
		} catch (Exception e) {
			hasError = true;
			log.append(String.format("====>价格Json转换出现异常：%s,%s\n", type, courseId, e.getMessage(), e.getStackTrace()));
		}
		
		if(floatPrice==null || floatPrice.size()==0){
			hasError = true;
			log.append(String.format("====>课程价格未设置或格式错误\n", type, courseId));
		}
		
		if(priceType==0){
			//忙时价格
			payMoney = floatPrice.get(0).getPrice();
		}else{
			//闲时价格
			for(PriceType pt : floatPrice){
				if(orderdCount>= pt.getStarton() && orderdCount<= pt.getEndon()){
					payMoney = pt.getPrice();
				}
			}
		}
		
		log.append(String.format("====>标价:%s\n", payMoney));
		
		if(hasError){
			logger.info(log.toString());
			return false;
		}
		
		/**第二步：计算优惠**/
		List<Promotion> promotions = autoClearDao.getPromotions(studentId);
		
		Course course = new Course(String.valueOf(courseId));
		
		if(promotions!=null && promotions.size()>0){
			course.setPriceNow(payMoney);
			course.setStudentId(studentId);
			course.setPriceType(priceType);
			//设置优惠
			course.addPromotions(promotions);
			//打折
			course.discount();
			
			for(Promotion promotion : promotions){
				log.append(String.format("====>优惠ID(%s) %s：%s元(原价：%s元,优惠前：%s元)\n",promotion.getId(), promotion.getPromotionName(),promotion.getMoney(),payMoney, promotion.getPreMoney()));
				
				//生成优惠记录
				Orderpromotions op = new Orderpromotions();
				op.setCourseorderId(orderId); //预约课程编号
				op.setPromotionId(StringUtils.toInteger(promotion.getId())); //促销编号
				op.setMoney(promotion.getMoney()); //促销金额
				op.setDescription(String.format("%s：%s元(原价：%s元,优惠前：%s元)",promotion.getPromotionName(),promotion.getMoney(),payMoney, promotion.getPreMoney())); //描述
				op.setCreateBy(new User("0"));
				op.setCreateDate(new Date());
				op.setUpdateBy(new User("0"));
				op.setUpdateDate(new Date());
				orderpromotionsService.save(op);
			}
		}
		
		/**第三步：生成交易记录**/
		Transrecord tr = new Transrecord();
		tr.setInout(1);// 收支类型，0收，1支 (以会员的角度)
		//3	普通课程
		//4	户外课程
		tr.setType("4");//交易类型 支的有：普通课程、户外课程； 收的有：1充值（即合同支付）、2请假资格返还、3取消资格返还，
		tr.setMoney(course.getPriceNow()); // 交易金额
		/*1	微信支付
		2	支付宝支付
		3	银联在线支付
		4	系统返还
		5	系统扣费
		6	现金支付*/
		tr.setPayType("5"); //支付方式（微信，支付宝，银联，现金）
		//tr.setPayCode("－"); //支付单号
		tr.setPayDate(new Date()); //发生日期
		tr.setDescription(String.format("自动扣费：%s元", tr.getMoney())); //描述
		tr.setMemberId(memberId); //会员编号
		tr.setStudentId(studentId); //学员编号
		tr.setCourseorderId(orderId); //预约课程编号
		tr.setContractId(contractId); //合同编号
		tr.setInvalid(0); //是否作废
		tr.setCreateBy(new User("0"));
		tr.setCreateDate(new Date());
		tr.setUpdateBy(new User("0"));
		tr.setUpdateDate(new Date());
		transrecordService.save(tr);
		
		log.append(String.format("====>生成交易记录(%s)，自动扣费：%s元\n",tr.getId(), tr.getMoney()));
		//throw new RuntimeException();
		//logger.info(log.toString());
		return true;
	}
}
